#include <iostream>
#include <fstream>
#include <string.h>
#include <time.h>
#include <math.h>
#include <WinSock2.h>
#include "tgaimage.h"
#include "model.h"
#include "geometry.h"
#include "rasterizer.h"

using namespace std;

const TGAColor white = TGAColor(255, 255, 255, 255);
const TGAColor red = TGAColor(255, 0, 0, 255);
const TGAColor green = TGAColor(0, 255, 0, 255);
const TGAColor blue = TGAColor(0, 0, 255, 255);

const int width = 800;
const int height = 800;
const int depth = 255;  

Model *model = NULL;
int *zbuffer = new int[width * height];
Vec3f light_dir = Vec3f(1, -1, 1).normalize();
Vec3f eye(1, 1, 3);
Vec3f center(0, 0, 0);
//Vec3f camera(0, 0, 3); 

#pragma region Test Code
Vec3f world2screen(Vec3f v) 
{
    return Vec3f(int((v.x + 1.) * width / 2. + .5), int((v.y + 1.) * height / 2. + .5), v.z);
}

#pragma endregion
   
Matrix lookat(Vec3f eye, Vec3f center, Vec3f up);

int main(int argc, char** argv) 
{
    if (2 == argc) model = new Model(argv[1]);
    else  model = new Model("obj/african_head.obj");

    zbuffer = new int[width * height];
    for (int i = 0; i < width * height; i++) 
    {
        zbuffer[i] = INT_MIN;
    }

    //Draw Model
    Matrix ModelView = lookat(eye, center, Vec3f(0, 1, 0));
    Matrix Projection = Matrix::identity(4);
    Matrix ViewPort = viewport(width / 8, height / 8, width * 3 / 4, height * 3 / 4);
    Projection[3][2] = -1.f / (eye - center).norm();

    //输出测试
    cerr << ModelView << endl;
    cerr << Projection << endl;
    cerr << ViewPort << endl;
    Matrix z = (ViewPort * Projection * ModelView);
    cerr << z << endl;

    TGAImage image(width, height, TGAImage::RGB);
    for (int i = 0; i < model->nfaces(); i++) 
    {
        vector<int> face = model->face(i);
        Vec3i screen_coords[3];
        Vec3f world_coords[3];
        float intensity[3];
        for (int j = 0; j < 3; j++) {
            Vec3f v = model->vert(face[j]);
            screen_coords[j] = Vec3f(ViewPort * Projection * ModelView * Matrix(v));
            world_coords[j] = v;
            intensity[j] = model->norm(i, j) * light_dir;
        }
        DrawTriangle(screen_coords, intensity, image, zbuffer);
    
    }

    image.flip_vertically(); 
    image.write_tga_file("output.tga");
    ShellExecute(NULL, NULL, "output.tga", NULL, NULL, SW_SHOWNORMAL);
    
    //Draw zbuffer
    /*TGAImage zbimage(width, height, TGAImage::GRAYSCALE);
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            zbimage.set(i, j, TGAColor(zbuffer[i + j * width], 1));
        }
    }
    zbimage.flip_vertically(); 
    zbimage.write_tga_file("zbuffer.tga");
       delete model;
    delete[] zbuffer;*/
    return 0;
}


Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) 
{
    Vec3f z = (eye - center).normalize();
    Vec3f x = (up ^ z).normalize();
    Vec3f y = (z ^ x).normalize();
    Matrix res = Matrix::identity(4);
    for (int i = 0; i < 3; i++) {
        //旋转子矩阵
        res[0][i] = x[i];
        res[1][i] = y[i];
        res[2][i] = z[i];
        //平移子矩阵
        res[i][3] = -center[i];
    }
    return res;
}
